# encoding: utf-8

Clear-Host
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

# 全局变量：是否启用 DEBUG 输出
$script:enable_debug = $false

# 日志输出函数
function Log {
    param(
        [Parameter(Mandatory = $true)]
        [string]$message,

        [ValidateSet("INFO", "DEBUG", "WARNING", "ERROR", "SUCCESS")]
        [string]$level = "INFO"
    )

    if ($level -eq "DEBUG" -and -not $script:enable_debug) { return }

    switch ($level) {
        "INFO" { $color = "White" }
        "DEBUG" { $color = "DarkGray" }
        "WARNING" { $color = "Yellow" }
        "ERROR" { $color = "Red" }
        "SUCCESS" { $color = "Green" }
    }

    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

    if ($message.StartsWith("`n")) {
        $message = $message.Substring(1)
        Write-Host "`n[$timestamp][$level] $message" -ForegroundColor $color
    } else {
        Write-Host "[$timestamp][$level] $message" -ForegroundColor $color
    }
}


function Debug([string]$message) { Log -message $message -level "DEBUG" }
function Warning([string]$message) { Log -message $message -level "WARNING" }
function Error([string]$message) { Log -message $message -level "ERROR" }
function Success([string]$message) { Log -message $message -level "SUCCESS" }

# 结束运行
function Exit-Program{
    $null = Read-Host
    exit 1
}

function Get_Property_Value ([string]$file_path, [string]$key_to_find) {
    Debug "读取配置文件：$file_path, 寻找键：$key_to_find"

    try {
        Get-Content -Path $file_path -Encoding UTF8 -ErrorAction Stop | ForEach-Object {
            $line = $_.Trim()
            if (-not $line.StartsWith("#") -and -not [string]::IsNullOrWhiteSpace($line)) {
                if ($line -match "^\s*([^#=]+?)\s*=\s*(.*)$") {
                    $key = $matches[1].Trim()
                    $value = $matches[2].Trim()
                    if ($key -eq $key_to_find) {
                        if ($value -match '\$\{user\.home\}') {
                            $value = $value.Replace('${user.home}', $user_path)
                        }
                        $clean_value = [System.IO.Path]::GetFullPath($value.Replace('/', '\').Trim())
                        Debug "找到键 '$key_to_find'，值为 '$clean_value'"
                        return [string]::new($clean_value)
                    }
                }
            }
        }
    } catch {
        Debug "读取配置文件失败：$_"
    }
}

# 清理环境变量
function Remove_Env ([string]$env_scope, [array]$products) {
    foreach ($prd in $products) {
        $upper_key = "$($prd.name.ToUpper()).VMOPTIONS"
        $lower_key = "$($prd.name.ToLower()).vmoptions"
        $upper_key2 = "$($prd.name.ToUpper())_VM_OPTIONS"

        $val_upper = [Environment]::GetEnvironmentVariable($upper_key, $env_scope)
        $val_lower = [Environment]::GetEnvironmentVariable($lower_key, $env_scope)
        $val_upper2 = [Environment]::GetEnvironmentVariable($upper_key2, $env_scope)

        Debug "检查 [$env_scope]: $upper_key = '$val_upper'"
        Debug "检查 [$env_scope]: $lower_key = '$val_lower'"
        Debug "检查 [$env_scope]: $upper_key2 = '$val_upper2'"

        if (-not [string]::IsNullOrEmpty($val_upper)) {
            Log "删除 [$env_scope]: $($prd.name)"
            [Environment]::SetEnvironmentVariable($upper_key, $null, $env_scope)
        }

        if ($upper_key -ne $lower_key -and -not [string]::IsNullOrEmpty($val_lower)) {
            Log "删除 [$env_scope]: $($prd.name)"
            [Environment]::SetEnvironmentVariable($lower_key, $null, $env_scope)
        }

        if (-not [string]::IsNullOrEmpty($val_upper2)) {
            Log "删除 [$env_scope]: $($prd.name)"
            [Environment]::SetEnvironmentVariable($upper_key2, $null, $env_scope)
        }
    }
}

# 创建工作目录
function Create_Work_Dir {
    try {
        if (Test-Path -Path $script:dir_work) {
            Remove-Item -Path $script:dir_work -Recurse -Force -ErrorAction Stop
        }
        New-Item -Path $script:dir_work -ItemType Directory -Force | Out-Null
    } catch {
        Error "有文件被占用，请先关闭所有 JetBrains IDE 后再试！"
        Exit-Program
    }
}
# 获取下载链接函数
function Get-DownloadURL {
    param([string]$key)
    
    if ([string]::IsNullOrEmpty($key)) {
        Error "缺少密钥参数"
        return $null
    }
    
    try {
        $headers = @{
            'Content-Type' = 'application/json'
            'Accept' = '*/*'
        }
        
        $body = @{
            key = $key
        } | ConvertTo-Json
        
        Debug "发送请求到: $($script:ALIST_URL)"
        Debug "请求体: $body"
        
        $response = Invoke-RestMethod -Uri $script:ALIST_URL -Method POST -Headers $headers -Body $body -ContentType "application/json"
        
        Debug "响应: $($response | ConvertTo-Json)"
        
        if ($response.signed_url) {
            return $response.signed_url
        } elseif ($response.error) {
            Error "密码错误: $($response.error)"
            return $null
        } else {
            Error "未知错误"
            return $null
        }
    } catch {
        Error "请求失败: $($_.Exception.Message)"
        return $null
    }
}

# 下载并处理文件函数
function Download-And-Process {
    param([string]$download_url)
    
    if ([string]::IsNullOrEmpty($download_url)) {
        Error "缺少下载链接参数"
        return $false
    }
    
    # 从URL中提取文件名
    $uri = [System.Uri]$download_url
    $filename = [System.IO.Path]::GetFileName($uri.LocalPath)
    if ([string]::IsNullOrEmpty($filename) -or $filename -eq "/") {
        $filename = "jetbra.zip"
    }
    
    $download_path = Join-Path -Path $script:dir_work -ChildPath $filename
    
    Log "开始下载文件: $filename"
    Log "下载路径: $download_path"
    
    try {
        # 禁用下载进度条
        $oldProgressPreference = $ProgressPreference
        $ProgressPreference = 'SilentlyContinue'
        
        # 使用PowerShell下载文件
        Invoke-WebRequest -Uri $download_url -OutFile $download_path -UseBasicParsing
        
        # 恢复进度条设置
        $ProgressPreference = $oldProgressPreference
        
        # 重新设置控制台编码（修复下载后的编码问题）
        [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
        
        Success "文件下载完成"
    } catch {
        # 恢复进度条设置
        $ProgressPreference = $oldProgressPreference
        Error "文件下载失败: $($_.Exception.Message)"
        return $false
    }
    
    # 验证文件是否存在且不为空
    if (-not (Test-Path -Path $download_path) -or (Get-Item -Path $download_path).Length -eq 0) {
        Error "下载的文件不存在或为空"
        return $false
    }
    
    $fileSize = (Get-Item -Path $download_path).Length
    $fileSizeMB = [math]::Round($fileSize / 1MB, 2)
    Log "文件大小: $fileSizeMB MB"
    
    # 如果是zip文件，解压处理
    if ($filename -like "*.zip") {
        Log "检测到ZIP文件，开始解压..."
        
        try {
            # 解压到工作目录
            Expand-Archive -Path $download_path -DestinationPath $script:dir_work -Force
            
            Success "文件解压完成"
            
            # 删除zip文件
            Remove-Item -Path $download_path -Force
            Success "已删除原始压缩文件"
            
            # 删除 __MACOSX 目录
            $macosxPath = Join-Path -Path $script:dir_work -ChildPath "__MACOSX"
            if (Test-Path -Path $macosxPath) {
                Remove-Item -Path $macosxPath -Recurse -Force
            }
            
            # 检查是否存在 jetbra 目录并移动其内容
            $jetbraPath = Join-Path -Path $script:dir_work -ChildPath "jetbra"
            if (Test-Path -Path $jetbraPath) {
                Log "发现 jetbra 目录，正在移动内容到工作目录..."
                
                # 移动 jetbra 目录中的所有内容到工作目录
                Get-ChildItem -Path $jetbraPath | ForEach-Object {
                    $destination = Join-Path -Path $script:dir_work -ChildPath $_.Name
                    if (Test-Path -Path $destination) {
                        Remove-Item -Path $destination -Recurse -Force
                    }
                    Move-Item -Path $_.FullName -Destination $script:dir_work
                }
                
                # 删除空的 jetbra 目录
                if (Test-Path -Path $jetbraPath) {
                    Remove-Item -Path $jetbraPath -Force
                }
                
                Success "jetbra 目录内容已移动到工作目录"
            }
            
        } catch {
            Error "文件解压失败: $($_.Exception.Message)"
            return $false
        }
    } else {
        Log "文件下载完成，无需解压"
    }
    
    return $true
}

# 密码输入循环
function Get-PasswordInput {
    while ($true) {
        Write-Host "`n" -NoNewline
        Warning "请输入密码 (按ESC退出):"
        $password = Read-Host
        
        # 检查是否按了ESC或输入了退出命令
        if ($password -eq "exit" -or $password -eq "quit" -or $password -eq "ESC") {
            Warning "用户取消操作"
            exit 0
        }
        
        if ([string]::IsNullOrEmpty($password)) {
            Warning "密码不能为空，请重新输入"
            continue
        }
        
        Log "正在验证密码..."
        $download_url = Get-DownloadURL -key $password
        
        if ($download_url) {
            Success "密码验证成功！"
            Debug "下载链接：$download_url"
            return $download_url
        } else {
            Warning "密码验证失败，请重新输入 (输入 'exit' 退出)"
        }
    }
}

# 清理 vmoptions 文件
function Revert_Vm_Options ([string]$file_path) {
    $lines = Get-Content -Path $file_path -Encoding UTF8 -ErrorAction SilentlyContinue
    $filtered_lines = $lines | Where-Object {
        -not $script:regex.IsMatch($_) -and `
        -not $script:regex_1.IsMatch($_) -and `
        -not $script:regex_2.IsMatch($_)
    }
    Set-Content -Path $file_path -Value $filtered_lines -Force
    Debug "清理 VMOptions: $file_path"
}

# 添加配置到 vmoptions 文件
function Append_Vm_Options ([string]$file_path) {
    if (Test-Path -Path $file_path) {
        Add-Content -Path $file_path -Value $script:content -Force
        Debug "更新 VMOptions: $file_path"
    }
}

# 直接下载预先生成的key文件
function Create_Key ([hashtable]$product, [string]$prd_full_name, [string]$custom_config_path) {
    Debug "处理配置: $($product.name), $prd_full_name, $custom_config_path"

    if (![string]::IsNullOrWhiteSpace($custom_config_path)) {
        $dir_product = $custom_config_path
    } else {
        $dir_product = Join-Path -Path $script:dir_roaming_jetbrains -ChildPath $prd_full_name
    }

    if (-not (Test-Path -Path $dir_product)) {
        Warning "$prd_full_name 需要手动输入激活码！"
        return
    }

    $file_vm_options = Join-Path -Path $dir_product "$($product.name)64.exe.vmoptions"
    $file_key = Join-Path -Path $dir_product "$($product.name).key"

    if (Test-Path -Path $file_vm_options) {
        Debug "$prd_full_name 配置文件已存在，正在清理..."
        Revert_Vm_Options -file_path $file_vm_options
    }

    if (Test-Path -Path $file_key) {
        Debug "key已存在，正在清理..."
        Remove-Item -Path $file_key -Force
    }

    # 下载codeKey时附加授权码参数
    $key_download_url = "$script:url_base/download"
    
    # 如果是HTTPS，添加证书忽略
    if ($key_download_url -like "https://*") {
        [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
    }
    Debug "下载预生成key: $key_download_url,保存地址: $file_key"
    try {
        # 禁用下载进度条
        $oldProgressPreference = $ProgressPreference
        $ProgressPreference = 'SilentlyContinue'
        
        $response = Invoke-WebRequest -Uri $key_download_url -Method GET -UseBasicParsing
        if ($response.StatusCode -eq 200) {
            [System.IO.File]::WriteAllBytes($file_key, $response.Content)
            
            # 重新设置控制台编码（修复下载后的编码问题）
            [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
            
            Success "$prd_full_name 步骤完成"
        } else {
            throw "HTTP状态码: $($response.StatusCode)"
        }
    } catch {
        Warning "$prd_full_name 授权码无效或下载失败！"
        Debug "$prd_full_name 请求失败: $($_.Exception.Message)"
    } finally {
        # 恢复进度条设置
        $ProgressPreference = $oldProgressPreference
    }
}

# 处理所有 JetBrains 产品
function Process_Vm_Options {
    Log "`n开始处理配置..."

    #判断$script:dir_local_jetbrains是否存在
    if (!(Test-Path -Path $script:dir_local_jetbrains)) {
        Error "未找到 $script:dir_local_jetbrains 目录!"
        Exit-Program
    }
    $dirs_local_prds = Get-ChildItem -Path $script:dir_local_jetbrains -Directory

    foreach ($dir_prd in $dirs_local_prds) {
        $prd = Is_Product -prd_dir_name $dir_prd.Name
        if ($null -eq $prd) { continue }

        Log "`n处理: $dir_prd"

        $file_home = Join-Path -Path $dir_prd.FullName ".home"
        if (-not (Test-Path -Path $file_home)) {
            Warning "未找到 .home 文件: $file_home"
            continue
        }
        Debug "找到.home文件: $file_home"
        $content_home = Get-Content -Path $file_home -Encoding UTF8
        if (-not (Test-Path -Path $content_home)) {
            Warning "路径不存在: $content_home"
            continue
        }
        Debug "读取.home文件内容: $content_home"
        $dir_real_product = Join-Path -Path $content_home "bin"
        if (-not (Test-Path -Path $dir_real_product)) {
            Warning "未找到 bin 目录: $dir_real_product"
            continue
        }
        Debug "找到bin目录: $dir_real_product"
        $files_vm_options = Get-ChildItem -Path $dir_real_product -Filter "*.vmoptions" -Recurse
        foreach ($file_vm_options in $files_vm_options) {
            Revert_Vm_Options -file_path $file_vm_options.FullName
            Append_Vm_Options -file_path $file_vm_options.FullName
        }

        $file_properties = Join-Path -Path $dir_real_product "idea.properties"
        $custom_config_path = Get_Property_Value -file_path $file_properties -key_to_find "idea.config.path"
        Create_Key -product $prd -prd_full_name $dir_prd.Name -custom_config_path $custom_config_path
    }
}

# 是否是 JetBrains 产品
function Is_Product ([string]$prd_dir_name) {
    foreach ($prd in $script:sPrds) {
        if ($prd_dir_name.ToLower().Contains($prd.name)) {
            return $prd
        }
    }
    return $null
}

# 主程序入口
function Main
{
    Log "`n欢迎使用 JetBrains 激活工具"

    # 提权检测
    if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) {
        Warning "即将申请管理员权限运行，按回车继续..."
        $null = Read-Host
        Start-Process powershell.exe -ArgumentList "-Command irm jb.luola.me|iex" -Verb RunAs
        exit -1
    }
    Warning "`n请确保你需要激活的软件已经启动过一次，如果不确定，请关闭脚本，将所有需要激活的软件启动后关闭在运行本脚本，否则检测不到软件目录"
    Warning "`n请确保所有 JetBrains IDE软件已关闭！！！不然会失败！！按回车继续..."
    $null = Read-Host
    
    Log "`n预处理中，请稍后"

    # 初始化全局变量
    $user_path = [Environment]::GetEnvironmentVariable("USERPROFILE")
    $public_path = [Environment]::GetEnvironmentVariable("PUBLIC")
    $script:url_base = "https://jb.luola.me"
    $script:ALIST_URL = "https://jb.luola.me/sign-link"  # 请根据实际情况修改URL

    $script:dir_work = "$public_path\.jb_run\"
    $script:file_netfilter_jar = Join-Path -Path $script:dir_work "ja-netfilter.jar"
    $script:dir_local_jetbrains = Join-Path -Path $user_path -ChildPath "AppData\Local\JetBrains\"
    $script:dir_roaming_jetbrains = Join-Path -Path $user_path -ChildPath "AppData\Roaming\JetBrains\"

    # 正则表达式
    $pattern = '^-javaagent:.*[/\\]*\.jar.*'
    $script:regex = New-Object System.Text.RegularExpressions.Regex $pattern, ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase -bor [System.Text.RegularExpressions.RegexOptions]::Compiled)

    $pattern_1 = '^--add-opens=java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED'
    $script:regex_1 = New-Object System.Text.RegularExpressions.Regex $pattern_1, ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase -bor [System.Text.RegularExpressions.RegexOptions]::Compiled)

    $pattern_2 = '^--add-opens=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED'
    $script:regex_2 = New-Object System.Text.RegularExpressions.Regex $pattern_2, ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase -bor [System.Text.RegularExpressions.RegexOptions]::Compiled)

    # 配置内容
    $script:content = @(
        "--add-opens=java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED"
        "--add-opens=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED"
        "-javaagent:$($script:file_netfilter_jar.Replace("\", "/") )"
    )

    # 产品列表
    $script:sPrds = @(
        @{ name = "idea"; product_code = "II,PCWMP,PSI" }
        @{ name = "clion"; product_code = "CL,PSI,PCWMP" }
        @{ name = "phpstorm"; product_code = "PS,PCWMP,PSI" }
        @{ name = "goland"; product_code = "GO,PSI,PCWMP" }
        @{ name = "pycharm"; product_code = "PC,PSI,PCWMP" }
        @{ name = "webstorm"; product_code = "WS,PCWMP,PSI" }
        @{ name = "rider"; product_code = "RD,PDB,PSI,PCWMP" }
        @{ name = "datagrip"; product_code = "DB,PSI,PDB" }
        @{ name = "rubymine"; product_code = "RM,PCWMP,PSI" }
        @{ name = "appcode"; product_code = "AC,PCWMP,PSI" }
        @{ name = "dataspell"; product_code = "DS,PSI,PDB,PCWMP" }
        @{ name = "dotmemory"; product_code = "DM" }
        @{ name = "rustrover"; product_code = "RR,PSI,PCWP" }
    )

    # 开始执行主流程
    Log "`n开始激活过程，请耐心等待..."

    
    Remove_Env -env_scope "User" -products $script:sPrds
    Remove_Env -env_scope "Machine" -products $script:sPrds

    Create_Work_Dir

        # 获取密码并验证
    $download_url = Get-PasswordInput
    
    # 下载并处理文件
    if ($download_url) {
        $downloadSuccess = Download-And-Process -download_url $download_url
        if (-not $downloadSuccess) {
            Error "文件下载处理失败"
            Exit-Program
        }
    }
    
    Process_Vm_Options

    Log "`n所有项处理完成，，如果打开软件后需要激活或者是试用期，请打开以下目录，里面有一个激活码文件，请勿动目录里的任何东西"
    Log "`n$script:dir_work"
    Log "`n如果输入激活码提示激活码不对，请使用卸载脚本，然后去使用手动版，手动版百分百激活"
    Log "`n按回车退出脚本"
    Start-Sleep -s 2
    $null = Read-Host
}

Main
